/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.umeox.moto.watch.themes.widget;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;

import com.umeox.moto.watch.themes.R;
import com.umeox.moto.watch.themes.skin.loader.ResourceManager;

import java.util.TimeZone;


/**
 * This widget display an analogic clock with two hands for hours and minutes.
 */
public class AnalogClock extends View {

    private static final String TAG = "AnalogClock";

    private final IntentFilter filter = new IntentFilter();

    private Time mCalendar;

    private Drawable mHourHand;
    private Drawable mMinuteHand;
    private Drawable mNail;

    private int mDialWidth;
    private int mDialHeight;
    private boolean mAttached;
    private Context mContext;

    private final Handler mHandler = new Handler();

    private float mMinutes;
    private float mHour;
    private boolean mChanged;

    private int TIME = 1000;

    Handler handler = new Handler();
    Runnable runnable = new Runnable() {

        @Override
        public void run() {
            try {
                onTimeChanged();
                invalidate();
                handler.postDelayed(this, TIME);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    /**
     * Create a new instance.
     *
     * @param context The application environment.
     */
    public AnalogClock(Context context) {
        this(context, null);
    }

    /**
     * Create a new instance.
     *
     * @param context The application environment.
     * @param attrs   A collection of attributes.
     */
    public AnalogClock(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * Create a new instance.
     *
     * @param context  The application environment.
     * @param attrs    A collection of attributes.
     * @param defStyle The default style to apply to this view.
     */
    public AnalogClock(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.AnalogClock, defStyle, 0);
        mHourHand = ResourceManager.getInstance().getDrawable(array.getResourceId(R.styleable.AnalogClock_hourHand,0));
        mMinuteHand = ResourceManager.getInstance().getDrawable(array.getResourceId(R.styleable.AnalogClock_minuteHand,0));
        mNail = ResourceManager.getInstance().getDrawable(array.getResourceId(R.styleable.AnalogClock_nailIcon,0));
        array.recycle();//定义完后属性对象回收

        mCalendar = new Time();

        DisplayMetrics dm =getResources().getDisplayMetrics();
        mDialWidth = dm.widthPixels;
        mDialHeight = dm.heightPixels;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        Log.i(TAG, "onAttachedToWindow()");
        if (!mAttached) {
            mAttached = true;
            filter.addAction(Intent.ACTION_SCREEN_ON);
            filter.addAction(Intent.ACTION_SCREEN_OFF);
            filter.addAction(Intent.ACTION_TIME_TICK);
            filter.addAction(Intent.ACTION_TIME_CHANGED);
            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
            getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
        }

        // NOTE: It's safe to do these after registering the receiver since the
        // receiver always runs
        // in the main thread, therefore the receiver can't run before this
        // method returns.

        // The time zone may have changed while the receiver wasn't registered,
        // so update the Time
        mCalendar = new Time();

        // Make sure we update to the current time
        onTimeChanged();

        //每秒刷新一次
//        post(runnable);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        if (mAttached) {
            getContext().unregisterReceiver(mIntentReceiver);
            removeCallbacks(runnable);
            mAttached = false;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        float hScale = 1.0f;
        float vScale = 1.0f;

        if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
            hScale = (float) widthSize / (float) mDialWidth;
        }

        if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
            vScale = (float) heightSize / (float) mDialHeight;
        }

        float scale = Math.min(hScale, vScale);

        setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
                resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mChanged = true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        boolean changed = mChanged;
        if (changed) {
            mChanged = false;
        }

        int availableWidth = getRight() - getLeft();
        int availableHeight = getBottom() - getTop();

        int x = availableWidth / 2;
        int y = availableHeight / 2;

        int w;
        int h;

        final Drawable hourHand = mHourHand;
        if (hourHand != null) {
            canvas.save();
            canvas.rotate(mHour / 12.0f * 360.0f, x, y);
            if (changed) {
                w = hourHand.getIntrinsicWidth();
                h = hourHand.getIntrinsicHeight();
                hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
            }
            hourHand.draw(canvas);
            canvas.restore();
        }

        final Drawable minuteHand = mMinuteHand;
        if (minuteHand != null) {
            canvas.save();
            canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);
            if (changed) {
                w = minuteHand.getIntrinsicWidth();
                h = minuteHand.getIntrinsicHeight();
                minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
            }
            minuteHand.draw(canvas);
            canvas.restore();
        }

        final Drawable mNailDrawable = mNail;
        if (mNailDrawable != null) {
            canvas.save();
            if (changed) {
                w = mNailDrawable.getIntrinsicWidth();
                h = mNailDrawable.getIntrinsicHeight();
                mNailDrawable.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
            }
            mNailDrawable.draw(canvas);
            canvas.restore();
        }
    }

    private void onTimeChanged() {
        mCalendar.setToNow();

        int hour = mCalendar.hour;
        int minute = mCalendar.minute;
        int second = mCalendar.second;

        mMinutes = minute + second / 60.0f;
        mHour = hour + mMinutes / 60.0f;
        mChanged = true;

        updateContentDescription(mCalendar);
    }

    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
                String tz = intent.getStringExtra("time-zone");
                mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
            }

            if (action.equals(Intent.ACTION_SCREEN_ON)) {
                Log.i(TAG, "Intent.ACTION_SCREEN_ON");
//                handler.postDelayed(runnable, TIME);
            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                Log.i(TAG, "Intent.ACTION_SCREEN_OFF");
            } else if (action.equals("MYALARMRECEIVER")) {  // handle alarm event
                Log.i(TAG, "Alarm Update time");
            }
            onTimeChanged();
            invalidate();
        }
    };

    private void updateContentDescription(Time time) {
        final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR;
        String contentDescription = DateUtils.formatDateTime(mContext, time.toMillis(false), flags);
        setContentDescription(contentDescription);
    }

    public void setHourHand(Drawable hourHand) {
        mHourHand = hourHand;
    }

    public void setMinuteHand(Drawable minuteHand) {
        mMinuteHand = minuteHand;
    }

    public void setNail(Drawable nail) {
        mNail = nail;
    }
}
